﻿#region copyright info
//------------------------------------------------------------------------------
// <copyright company="ChaosStudio">
//     Copyright (c) 2002-2010 巧思工作室.  All rights reserved.
//     Contact:		MSN:zhouyu@cszi.com , QQ:478779122
//		Link:				http://www.69sea.com http://www.cszi.com
// </copyright>
//------------------------------------------------------------------------------
#endregion

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using CS.Util.Text;

namespace CS.TaskScheduling
{
    /// <summary>
    ///   单一任务配置信息
    /// </summary>
    /// 
    /// <description class = "CS.Model.TaskInfo">
    ///   
    /// </description>
    /// 
    /// <history>
    ///   2010/4/4 17:45:21 , zhouyu ,  创建	     
    ///  </history>
    [Serializable, XmlRoot(ElementName = "task")]
    public class TaskInfo
    {
        /// <summary>
        /// 默认构造
        /// </summary>
        public TaskInfo()
        {
            Job = new JobInfo { Id = Guid.NewGuid().ToString() };
            WorkSetting = new WorkSettingInfo { DelaySecond = 2, ErrorWay = ErrorWayType.Sleep, Interval = new TimeSpan(1, 1, 1, 1), SleepInterval = new TimeSpan(1, 1, 1, 1), WorkTrigger = "0 10 0 ? * *" };    //默认每天0:10分执行
            Extend = new object();
        }

        /// <summary>
        /// 该任务反射Type
        /// </summary>
        [XmlAttribute("type")]
        public string Type { get; set; }

        /// <summary>
        /// 任务是否启用
        /// </summary>
        [XmlAttribute("enable")]
        public bool Enable { get; set; }

        /// <summary>
        /// 工作信息
        /// </summary>
        [XmlElement(ElementName = "job")]
        public JobInfo Job { get; set; }

        /// <summary>
        /// 工作执行时间设定
        /// </summary>
        [XmlElement("workSetting")]
        public WorkSettingInfo WorkSetting { get; set; }


        //#region 预定义的扩展 PreExtend

        //[XmlElement(ElementName = "preExtend")]
        //public PreExtend PreExtend { get; set; }

        //#endregion


        #region 自定义的扩展配置 GetExtend

        /// <summary>
        /// 结合该任务的扩展配置类，内部使用，请使用GetExtend获取该扩展实例。
        /// </summary>
        [XmlElement("extend")]
        public object Extend { get; set; }

        /// <summary>
        /// 获取已设定的扩展类型实例
        /// </summary>
        /// <typeparam name="T">扩展的类型</typeparam>
        /// <returns>扩展类实例</returns>
        public T GetExtend<T>() where T : class
        {
            return Serializer.XmlDeserializerFormText<T>(ExtendRawXml);
        }

        /// <summary>
        /// Extend扩展的Xml片断
        /// </summary>
        /// <returns></returns>
        protected string ExtendRawXml
        {
            get
            {
                var nodes = Extend as XmlNode[];
                if (nodes == null || nodes.Length == 0)
                    return "<extend />";
                var w = new StringWriter();
                XmlWriter writer = new XmlTextWriter(w);
                writer.WriteStartElement("extend");
                foreach (var node in nodes)
                    writer.WriteRaw(node.OuterXml);

                writer.WriteEndElement();
                writer.Close();
                return w.ToString();
            }
        }
        #endregion


        #region 方法 CalculateLaunchTime

        /// <summary>
        /// 计算任务(单个)的启动时间[当前计算机所处时区]
        /// </summary>
        /// <returns></returns>
        public DateTime? CalculateLaunchTime()
        {           
            // 不可运行下次不用执行
            if (!Enable)
            {
                Job.Execution.Status = TaskStatusType.Disable;
                return null;
            }

            var now = SystemTime.Now();
            DateTime? runTime = now.AddSeconds(WorkSetting.DelaySecond);

            //首次运行的任务
            if(Job.Execution.LastSucceedRun == null)
            {
                return runTime.Value;
            }

            //已经成功运行过的
            var cronExp =  new CronExpression(WorkSetting.WorkTrigger);
             runTime = cronExp.GetNextValidTimeAfter(Job.Execution.LastSucceedRun.Value.ToUniversalTime());
             if (runTime == null)
            {
                Job.Execution.Status = TaskStatusType.Disable;
                return null;
            }
            

             return runTime.Value.ToLocalTime();

        }


        #endregion


    }



    #region 任务基本信息 JobInfo

    /// <summary>
    /// 任务属性
    /// </summary>
    [Serializable]
    public class JobInfo
    {
        /// <summary>
        /// 任务Id，必须有
        /// </summary>
        [XmlAttribute("id")]
        public string Id { get; set; }

        /// <summary>
        /// 任务名称
        /// </summary>
        [XmlAttribute("name")]
        public string Name { get; set; }

        /// <summary>
        /// 任务是否要自动补全
        /// </summary>
        [XmlAttribute("isPatch")]
        public bool IsPatch { get; set; }

        /// <summary>
        /// 本任务运行情况
        /// </summary>
        public ExecutionInfo Execution { get; set; }
    }

    #endregion


    #region 任务运行状态 ExecutionInfo

    /// <summary>
    /// 任务运行状态
    /// </summary>
    [Serializable]
    public class ExecutionInfo
    {
        /// <summary>
        /// 任务配置是否还存在
        /// </summary>
        [XmlIgnore]
        public bool IsExsit { get; set; }

        /// <summary>
        /// 最后运行时间
        /// </summary>
        public DateTime? LastRun { get; set; }

        /// <summary>
        /// 最后成功运行的时间 
        /// 新任务时为null , 只有补全功能需要时才使用。每次成功运行后更新该值。
        /// Note:主要目的是用于补全时使用的
        /// </summary>
        public DateTime? LastSucceedRun { get; set; }

        /// <summary>
        /// 正确运行的次数
        /// </summary>
        [XmlAttribute]
        public int RunTimes { get; set; }

        /// <summary>
        /// 错误运行时休眠的次数
        /// </summary>
        [XmlAttribute]
        public int SleepTimes { get; set; }
        
        /// <summary>
        /// 任务状态
        /// Note:状态是给人看的，不是判断任务是否执行的依据。
        /// </summary>
        [XmlAttribute]
        public TaskStatusType Status { get; set; }


        ////Todo:太诡异了，这两个特性竟然不起作用。
        //[OnDeserialized]
        //internal void OnDeserialized(StreamingContext context)
        //{
        //    log.DebugFormat("反序列化结束... :{0}", Status);
        //  //  Status = TaskStatusType.Default;
        //}

        //[OnDeserializing]
        //internal void OnDeserializing(StreamingContext context)
        //{

        //    Console.Write(string.Format("反序列化开始... :{0}", context.State));
        //    //Status = TaskStatusType.Default;
        //}

        //private log4net.ILog log = log4net.LogManager.GetLogger(typeof(ExecutionInfo));

    }

    #endregion


    #region 任务运行范围 WorkSettings

    /// <summary>
    /// 该任务所有时间运行执行范围
    /// </summary>
    [Serializable]
    public class WorkSettingInfo
    {
        /// <summary>
        /// 需要时的任务延时，秒
        /// </summary>
        [XmlAttribute("delaySecond")]
        public int DelaySecond { get; set; }

        /// <summary>
        /// 发生错误时的后续操作
        /// </summary>
        [XmlAttribute("whenErrorHappened")]
        public ErrorWayType ErrorWay { get; set; }

        /// <summary>
        /// 运行时间字符串设定
        /// Note: * 可以被用来表示域中“每个”可能的值 , 
        /// </summary>
        [XmlElement("workTrigger")]
        public string WorkTrigger { get; set; }

        /// <summary>
        /// 正常时的运行间隔
        /// </summary>
        [XmlElement("interval")]
        public WorkTimeSpan Interval { get; set; }

        /// <summary>
        /// 错误时的运行时休眠的间隔
        /// </summary>
        [XmlElement("sleepInterval")]
        public WorkTimeSpan SleepInterval { get; set; }
        
    }

    #endregion



    #region 错误发生时后续操作枚举 ErrorWayType

    /// <summary>
    /// 错误发生时后续操作枚举
    /// </summary>
    public enum ErrorWayType
    {
        /// <summary>
        /// 默认，一直执行下去，直到执行成功完成任务。
        /// </summary>
        Default = 0,

        /// <summary>
        /// 停止执行,等待明天
        /// </summary>
        Stop = 1,

        /// <summary>
        /// 休眠后执行，直到失败次数执行完成后停止
        /// </summary>
        Sleep = 2,
        
    }


    #endregion


    #region 任务执行状态 TaskStatusType

    /// <summary>
    /// 任务执行状态
    /// </summary>
    [Flags]
    public enum TaskStatusType
    {
        /// <summary>
        /// 默认，需要计算后判断是否要执行
        /// </summary>
        Default = 0,

        /// <summary>
        /// 当前运行状态为不可用，禁止运行
        /// </summary>
        Disable = 1,

        /// <summary>
        /// 任务运行中，有下次执行时间
        /// </summary>
        Runing = 2,

        /// <summary>
        /// 正在以错误状态运行休眠中
        /// </summary>
        Sleeping = 4,

        /// <summary>
        /// 今天运行完成
        /// </summary>
        TodayComplete = 8,

        /// <summary>
        /// 今天未正常运行完成，如果要补全的任务的话就要启用补全功能了
        /// </summary>
        TodayNotComplete = 16,

        ///// <summary>
        ///// 正在暂停
        ///// </summary>
        //Pausing = 32,

        /// <summary>
        /// 任务被暂停
        /// </summary>
        Pasuse = 64,


        ///// <summary>
        ///// 正在停止
        ///// </summary>
        //Stoping = 128,

        /// <summary>
        /// 任务停止了
        /// </summary>
        Stop = 256,

        /// <summary>
        /// 任务完成，再也不用执行了 [超出运行时间设定]
        /// </summary>
        Complete = 512,

        /// <summary>
        /// 该任务已被移除
        /// </summary>
        Removed = 1024,

    }

    #endregion


    #region 任务集合 TaskCollection

    /// <summary>
    /// 任务配置集合，只读
    /// </summary>
    [Serializable]
    public class TaskCollection : List<TaskInfo>
    {
        /// <summary>
        /// 按工作Id的索引
        /// </summary>
        /// <param name="jobId">工作Id</param>
        /// <returns></returns>
        public TaskInfo this[string jobId]
        {
            get { return Find(x => x.Job.Id == jobId); }
        }
    }

    #endregion


    #region 任务运行状态集合 TaskExecutionCollection

    /// <summary>
    /// 任务运行状态集合
    /// </summary>
    [Serializable]
    public class JobExecutionCollection : List<JobInfo>
    {
        /// <summary>
        /// 按工作Id索引返回执行信息
        /// Todo:使用int的Id时会出现错乱。最后一个内容序列化不出来。
        /// </summary>
        /// <param name="jobId">工作Id</param>
        /// <returns>工作信息</returns>
        public JobInfo this[string jobId]
        {
            get
            {
                var job = Find(x => x.Id == jobId);
                return job;
            }
            set
            {
                var job = Find(y => y.Id == jobId);
                job = value;
            }
        }

    }

    #endregion




    #region 可序列化的TimeSpan WorkTimeSpan

    /// <summary>
    /// 可以序列化的MyTimeSpan
    /// TimeSpan 不能继承
    /// </summary>
    public class WorkTimeSpan
    {
        private TimeSpan timeSpan;

        public WorkTimeSpan()
        { }

        public WorkTimeSpan(TimeSpan time)
        {
            timeSpan = time;
        }

        /// <summary>
        /// 执行次数
        /// </summary>
        [XmlAttribute("times")]
        public int Times { get; set; }

        /// <summary>
        /// 仅供序列化使用，不要直接读取该值。
        /// </summary>
        [XmlText]
        public string XmlText
        {
            get { return timeSpan.ToString(); }
            set { timeSpan = TimeSpan.Parse(value); }
        }

        /// <summary>
        /// 隐式转换 MyTimeSpan -> TimeSpan
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static implicit operator TimeSpan(WorkTimeSpan t)
        {
            return t.timeSpan;
        }

        /// <summary>
        /// 隐式转换 TimeSpan -> MyTimeSpan
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static implicit operator WorkTimeSpan(TimeSpan t)
        {
            return new WorkTimeSpan(t);
        }

        /// <summary>
        /// 重写ToString方法
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return timeSpan.ToString();
        }

    }

    #endregion


    #region 任务运行结果
    
    /// <summary>
    /// 任务执行结果
    /// </summary>
    public class Result
    {
        /// <summary>
        /// 运行结果枚举
        /// </summary>
        public ResultType Stamp { get; set; }

        /// <summary>
        /// 任务返回的消息
        /// </summary>
        public string Message { get; set; }
    }

    /// <summary>
    /// 运行结果的枚举
    /// (注意:不能正负混用)
    /// <para>这个关系到任务的运行结果</para>
    /// </summary>
    [Flags]
    public enum ResultType
    {
        /// <summary>
        /// 未知
        /// </summary>
        Unknow = 0,

        /// <summary>
        /// 真,有效的执行
        /// </summary>
        True = 1,

        /// <summary>
        /// 假,无效的运行，空转中...
        /// </summary>
        False = 2,

        /// <summary>
        /// 执行成功，全部成功后(Finnished)才会更新最后成功执行日期
        /// </summary>
        Succeed = 4,

        /// <summary>
        /// 执行失败,返回该值时可能会让该任务休眠或是立即停止
        /// </summary>
        Failed = 8,

        /// <summary>
        /// 任务完成，可以直接停止了。更新最后执行成功的时间，使得本任务的触发时间改为下一轮触发。
        /// </summary>
        Finished = 16,


    }


    #endregion

}